<?php

namespace app\admin\controller;
use think\App;
use think\Exception;
use think\exception\FuncNotFoundException;
use think\exception\HttpException;
use think\exception\ValidateException;
use app\BaseController;
use think\facade\Db;
use app\admin\model\AdminToken as AdminTokenModel;

class Admin extends BaseController
{
    // token解码的用户信息
    protected $userInfo = [];

    /**
     * 初始化
     */
    protected function initialize(){
        try{
            // 构造当前URL
            $controller = $this->request->controller();
            $action = $this->request->action();
            $app = app('http')->getName();
            $url =  "{$app}/{$controller}/{$action}";
            // 载入基本配置
            $list = db('admin_config')->select()->column('data','name');
            config($list,'admin_config');
            // 如果当前URL不是匿名访问的，执行Token检查
            if(!in_array($url,config('rds.nocheck'))) $this->checkToken();
            // 记录操作日志
            event('DoLog',$this->userInfo);	//写入操作日志
        } catch (\Exception $exception){
            throw $exception;
        }

    }

    /**
     * 生成Token
     * @param $data
     * @return string
     */
    protected function setToken($data){
        try {
            // 生成Token
            $token = signToken($data);
            //登录的时候把token写入数据表
            $tokenInfo = AdminTokenModel::where('token',$token)->findOrEmpty();
            // 如果没有写入数据库
            if($tokenInfo->isEmpty()){
                // 不是多用户登录，即单点登录，则更新状态为下线状态
                if(!config('rds.multiple_login')){
                    // dev_status = 0 为下线状态
                    AdminTokenModel::field('dev_status')->where('username',$data['username'])->update(['dev_status'=>0]);
                }
                // 无论是单点登录还是允许多终端登录，都记录此用户的登录数据
                AdminTokenModel::create(['token'=>$token,'username'=>$data['username']]);
            }
            return $token;
        } catch (\Exception $e){
            throw new ValidateException($e->getMessage());
        }
    }

    /**
     * 检查Token
     */
    protected function checkToken(){
        //检测ip白名单
        $ips = config('admin_config.ip_white');
        if($ips){
            if(!in_array($this->request->ip(),preg_split('/\n/',$ips))){
                throw new ValidateException('请求ip来源错误');
            }
        }
        // 从请求header中取出Token
        $token = $this->request->header('Authorization');
        // 没有取到Token
        if(!$token) abort(101,'Token不能为空');
        // 取到的Token格式不对
        if(count(explode('.',$token)) <> 3) abort(101,'Token格式错误');
        // 从系统表中查找此Token
        $tokenInfo = AdminTokenModel::where('token',$token)->findOrEmpty();
        // 没有查找到记录
        if($tokenInfo->isEmpty()) abort(101,'登录状态已失效，请重新登录');
        // 查看此Token的状态
        if(!$tokenInfo['status']) abort(101,'登录状态已过期，请重新登录');
        // 是否存在单点登录限制
        if(!$tokenInfo['dev_status']) abort(101,'你已下线,账户在其它设备登录!');
        // 验证Token
        $verifyResult = checkToken($token);
        if($verifyResult['status']){
            $this->userInfo = $verifyResult['data'];
        } else {
            abort(101,$verifyResult['info']);
        }
    }



    /**
     * 格式化sql字段查询
     * 转化为  label => value 结构
     * 根据是否有第三个字段确定是否是嵌套结构
     * @param $sql
     * @return array|mixed
     */
    protected function query($sql){
        preg_match_all('/select(.*)from/iUs',$sql,$all);
        $array = [];
        $sqlvalue = explode(',',trim($all[1][0]));
        if(count($sqlvalue) == 1) {
            // 查询字典，不存在数据隔离
            $sql = str_replace(config('rds.table_name_prefix'),config('database.connections.mysql.prefix'),$sql);
            $list = Db::query($sql);
            $array = json_decode($list[0]['data'],true);
        } else {
            // SQL查询前缀替换
            $sql = strtolower($sql);
            if(!strpos($sql,'creater_id')){
                $position = strpos($sql,'from');
                $sql = substr($sql, 0, $position) . ',creater_id ' . substr($sql, $position);
            }
            $sql = str_replace(config('rds.table_name_prefix'),config('database.connections.mysql.prefix'),$sql);
            $list2 = loadList($sql,$this->whereFormat([],'sql','a'));
            $list = $list2['data'];
            $alisa = array_keys($list[0]);
            foreach($list as $k=>$v){
                $array[$k]['label'] = $v[$alisa[1]];
                $array[$k]['value'] = $v[$alisa[0]];
                if($alisa[2]){
                    $array[$k]['pid'] = $v[$alisa[2]];
                }
            }
        }
        return $array;
    }


    /**
     * 获取所有菜单
     * @return array
     */
    protected function getTotalMenus(){
        $menu =  $this->getBaseMenus();
        $order_array = array_column($menu, 'sortid');
        array_multisort($order_array,SORT_ASC,$menu );
        return $menu;
    }


    /**
     * 返回当前应用的菜单列表
     * @return array
     */
    protected function getBaseMenus(){
        try {
            $field = 'menu_id,pid,title,controller_name,status,icon,sortid,component_path';
            $list = db("sys_menu")
                ->field($field)
                ->where(['status'=>1,'app_id'=>1])
                ->order('sortid asc')
                ->select()
                ->toArray();
            if($list){
                foreach($list as $key=>$val){
                    $menus[$key]['name']    = $val['controller_name'];
                    $menus[$key]['pid']     = $val['pid'];
                    $menus[$key]['menu_id'] = $val['menu_id'];
                    $menus[$key]['title']   = $val['title'];
                    $menus[$key]['sortid']  = $val['sortid'];
                    $menus[$key]['icon']    = $val['icon'] ? $val['icon'] : 'el-icon-menu';
                    $menus[$key]['path']    = (string)url('admin/'.str_replace('/','.',$val['controller_name']).'/index');
                    $menus[$key]['component_path'] = $val['component_path'];
                }
                return _generateListTree($menus,0,['menu_id','pid']);
            }
        } catch (\Exception $e){
            throw new ValidateException($e->getMessage());
        }
    }

    /**
     * 获取要加载的组件
     * @param $menu
     * @return array
     */
    protected function getComponents($menu){
        $components = [];
        foreach($menu as $v){
            $components[] = [
                'name'  =>  $v['name'],
                'path'  =>  $v['path'],
                'meta' =>  [
                    'title'    =>  $v['title'],
                ],
                'component_path'    =>  $v['component_path']
            ];
            if($v['children']){
                $components = array_merge($components,$this->getComponents($v['children']));
            }
        }
        return $components;
    }


    /**
     * 获取隐藏了菜单但是也要加载的组件
     * @param $roleIds 用户所属角色数组
     * @return array
     */
    protected function getHiddenComponents($roleIds,$accessList){
        try {
            $list = db("sys_menu")
                ->field('controller_name,title,component_path')
                ->where('app_id',1)
                ->where('status',0)
                ->where('component_path','<>','')
                ->select()
                ->toArray();
            $components = [];
            foreach($list as $v){
                if(in_array(1, $roleIds) || in_array($v['controller_name'],$accessList)){
                    $components[] = [
                        'name'  =>$v['controller_name'],
                        'path'  =>(string)url('admin/'.str_replace('/','.',$v['controller_name']).'/index'),
                        'meta'  =>['title'=>$v['title']],
                        'component_path'=>$v['component_path']
                    ];
                }
            }
            return $components;
        } catch (\Exception $e){
            throw new ValidateException($e->getMessage());
        }
    }



    /**
     * 根据菜单ID获取sort_id之前的字段名
     * @param $menu_id
     * @return mixed|string
     */
    public function getAtferFieldName($menu_id){
        try {
            $fields = db('sys_field')
                ->where(['menu_id'=>$menu_id,'create_table_field'=>1])
                ->order('sortid','asc')
                ->select()
                ->toArray();
            $afterField = '';
            foreach ($fields as $key => $value){
                if($value['field'] == 'sort_id'){
                    $afterField = $fields[$key -1]['field'];
                }
            }
            if(empty($afterField)){
                return $fields[count($fields)-1]['field'];
            } else {
                return $afterField;
            }
        } catch (\Exception $e){
            throw new ValidateException($e->getMessage());
        }
    }

    public function __call($method, $args){
        \think\facade\Log::record('app/admin/controller/Admin.php');
        \think\facade\Log::record(__CLASS__.':'.$method);
        throw new FuncNotFoundException('方法不存在',$method);
    }


    // 更改数据隔离策略和数据列表查询方法

    /**
     * 格式化sql字段查询
     * 转化为  label => value 结构
     * 根据是否有第三个字段确定是否是嵌套结构
     * @param $sql
     * @return array|mixed
     */
    protected function query_v2($sql){
        preg_match_all('/select(.*)from/iUs',$sql,$all);
        $array = [];
        $sqlvalue = explode(',',trim($all[1][0]));
        if(count($sqlvalue) == 1) {
            // 查询字典，不存在数据隔离
            $sql = str_replace(config('rds.table_name_prefix'),config('database.connections.mysql.prefix'),$sql);
            $list = Db::query($sql);
            $array = json_decode($list[0]['data'],true);
        } else {
            // SQL查询前缀替换
            $sql = strtolower($sql);
            if(!strpos($sql,'creater_id')){
                $position = strpos($sql,'from');
                $sql = substr($sql, 0, $position) . ',creater_id,creater_dept ' . substr($sql, $position);
            }
            $sql = str_replace(config('rds.table_name_prefix'),config('database.connections.mysql.prefix'),$sql);
            $list = \think\facade\Db::table('(' . $sql . ') as a')
                // ->where($this->whereFormat([]))
                ->whereRaw($this->whereScope())
                ->select()
                ->toArray();
            if($list){
                $alisa = array_keys($list[0]);
                foreach($list as $k=>$v){
                    $array[$k]['label'] = $v[$alisa[1]];
                    $array[$k]['value'] = $v[$alisa[0]];
                    if($alisa[2]){
                        $array[$k]['pid'] = $v[$alisa[2]];
                    }
                }
            } else {
                $array = [];
            }
        }
        return $array;
    }

    /**
     * 查询自动处理数据权限
     * @param $where
     * @param $alias
     * @return string
     */
    public function whereScope($alias = null): string
    {
//         \think\facade\Log::record('$this->userInfo');
//         \think\facade\Log::record($this->userInfo);
        $whereRaw = '';
        switch ($this->userInfo['permission']) {
            case 1:
                // 全部数据权限
                $whereRaw .= '1=1';
                break;
            case 2:
                // 部门及子部门数据
                $field_dept = $alias ? $alias . '.' . 'creater_dept' : 'creater_dept';
                $dept_ids = $this->getUserAllDeptIds();
                $whereRaw .= $field_dept . ' in (' . $dept_ids . ')';
                $field_user = $alias ? $alias . '.' . 'creater_id' : 'creater_id';
                $whereRaw .= ' OR ' . $field_user . ' = ' . $this->userInfo['user_id'];
                break;
            case 3:
                // 本部门数据
                $field_dept     =   $alias ? $alias . '.' . 'creater_dept' : 'creater_dept';
                $whereRaw       .=  $field_dept . ' = ' . $this->userInfo['dept_id'];
                $field_user     =   $alias ? $alias . '.' . 'creater_id' : 'creater_id';
                $whereRaw       .=  ' OR ' . $field_user . ' = ' . $this->userInfo['user_id'];
                break;
            case 4:
                // 本人数据
                $field_user     =   $alias ? $alias . '.' . 'creater_id' : 'creater_id';
                $whereRaw       .=  $field_user . ' = ' . $this->userInfo['user_id'];
                break;
            case 5:
                // 指定部门
                if($this->userInfo['dept_ids']){
                    $field_dept = $alias ? $alias . '.' . 'creater_dept' : 'creater_dept';
                    $dept_ids = $this->userInfo['dept_ids'];
                    $whereRaw .= $field_dept . ' in (' . $dept_ids . ') OR ';
                }
                $field_user     =   $alias ? $alias . '.' . 'creater_id' : 'creater_id';
                $whereRaw       .=  $field_user . ' = ' . $this->userInfo['user_id'];
                break;
            case 6:
                // 无数据权限
                $whereRaw .= '1 != 1';
                break;
            default:
                throw new ValidateException('无效数据权限！');
        }
//         \think\facade\Log::record('$whereRaw');
//         \think\facade\Log::record($whereRaw);
        return $whereRaw;
    }

    /**
     * 查询用户所在部门及子部门的所有用户id
     * @return array
     */
    private function getUserAllDeptIds(){
        $dept_id = $this->userInfo['dept_id'];
        // 查询本员工所在部门的所有子部门的部门ID
        $sql = '(SELECT dept_id FROM ';
        $sql .= '(SELECT t1.dept_id,t1.NAME,IF(FIND_IN_SET(pid, @pids) > 0,@pids := CONCAT(@pids, ",", dept_id),0) AS ischild ';
        $sql .= "FROM (SELECT dept_id,pid,NAME FROM cd_admin_dept t ORDER BY pid,dept_id) t1,(SELECT @pids := " . $dept_id . ") t2) t3 ";
        $sql .= 'WHERE ischild != 0)';
        $dept_id_array = \think\facade\Db::table([$sql => 'a'])->column('dept_id');
        // 追加员工自己的部门id
        if(count($dept_id_array)>0){
            $dept_ids =  implode(',',$dept_id_array) . ',' . $dept_id;
        } else {
            $dept_ids = $dept_id;
        }
        return $dept_ids;
    }

}
